#include <iostream>
#include <vector>
#include <sstream>
#include <fstream>
#include <cmath>
#include <cstdlib>

#include <algorithm>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <map>
#include <unordered_map>
#include <set>

using namespace std;


template<typename T>
T* mallocArray(int n) {
	T* arr = (T*)malloc(n * sizeof(T));
	return arr;
}
template<typename T>
void freeArray(T* arr) {
	if(arr != NULL){
        free(arr);
	}
}

string testFile = "/data/test_data.txt";
string resultFile = "/projects/student/result.txt";

int max_record_num = 280000;
int node_num = 0;
typedef uint account;
typedef vector<account> Loop;
vector<Loop> loops3, loops4, loops5, loops6, loops7, all_loops;

map<account, set<account>> toMap; //map会自动按照key排序
vector<uint> nodes;
unordered_map<uint,int> idHash;
vector<vector<int>> G;

vector<bool> vis;
vector<int> pathS;

inline unsigned int parse(char** s){
	char *p = *s;
	unsigned int val = *(p++) - '0';
	while(*p != ','){
		val = 10*val + *(p++) - '0';
	}
	*s = p+1;
	return val;
}
void loadData_and_createGrap(){
	int fd = open(testFile.c_str(), O_RDONLY);
    int file_size = lseek(fd, 0, SEEK_END);
    char* p_map =(char*)mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
    close(fd);
	char *p = p_map;
	account a1,a2;
	while(*p != '\0'){
		a1 = parse(&p);
		a2 = parse(&p);
		toMap[a1].insert(a2);
		nodes.emplace_back(a1);
		nodes.emplace_back(a2);
		while(*p != '\n'){p++;}
		p++;
	}
	sort(nodes.begin(),nodes.end());
	nodes.erase(unique(nodes.begin(),nodes.end()),nodes.end());
	for(uint& v:nodes) idHash[v] = node_num++;
	G=vector<vector<int>>(node_num);
	map<account, set<account>>::iterator iter, end;
	end = toMap.end();
	int v;
	for(iter=toMap.begin(); iter!=end; ++iter){
		v = idHash[iter->first];
		for(uint u:iter->second) G[v].emplace_back(idHash[u]);
	}
	munmap(p_map, file_size);
}

inline void handleLoop(const Loop& loop){
	switch(loop.size()){
		case 3:
			loops3.emplace_back(loop);
			break;
		case 4:
			loops4.emplace_back(loop);
			break;
		case 5:
			loops5.emplace_back(loop);
			break;
		case 6:
			loops6.emplace_back(loop);
			break;
		case 7:
			loops7.emplace_back(loop);
			break;
	}
}

void dfs(int head,int cur,int depth,vector<int> &path){
	vis[cur]=true;
	path.push_back(cur);
	for(int &v:G[cur]){
		if(v==head && depth>=3 && depth<=7){
			Loop tmp;
			for(int &x:path)
				tmp.push_back(nodes[x]);
			handleLoop(tmp);
		}
		if(depth<7 && !vis[v] && v>head){
			dfs(head,v,depth+1,path);
		}
	}
	vis[cur]=false;
	path.pop_back();
}

void solve(){
	vis=vector<bool>(node_num,false);
	for(int i=0;i<node_num;i++){
		if(!G[i].empty()){
			dfs(i,i,1,pathS);
		}
	}
}
char buf[77*3*1000000];
char* p = buf;

void uint_to_char(const Loop& loop){
	string tmp = to_string(loop[0]);
	int size = tmp.size();
	memcpy(p, tmp.c_str(), size);
	p += size;
	for(int i=1; i<loop.size(); i++){
		tmp = to_string(loop[i]);
		size = tmp.size();
		*(p++) = ',';
		memcpy(p, tmp.c_str(), size);
		p += size;
	}
	*(p++) = '\n';
}

void save(){
	int num = loops3.size()+loops4.size()+loops5.size()+loops6.size()+loops7.size();
	string tmp = to_string(num);
	int size = tmp.size();
	memcpy(p, tmp.c_str(), size);
	p += size;
	*(p++) = '\n';
	for(auto& loop:loops3) uint_to_char(loop);
	for(auto& loop:loops4) uint_to_char(loop);
	for(auto& loop:loops5) uint_to_char(loop);
	for(auto& loop:loops6) uint_to_char(loop);
	for(auto& loop:loops7) uint_to_char(loop);
	int data_size = p - buf;
	int fd = open(resultFile.c_str(), O_RDWR|O_CREAT, 0666);
	ftruncate(fd, data_size);
	char* p_map =(char*)mmap(NULL, data_size, PROT_WRITE, MAP_SHARED, fd, 0);
	memcpy(p_map, buf, data_size);
	munmap(p_map, data_size);
	close(fd);
}

int main(int argc, char* argv[]){
	loadData_and_createGrap();
	solve();
	save();
	return 0;
}